package UDP.Demo3;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.List;

/**

 * 基于UDP协议的聊天室服务器

 * 支持多客户端连接、消息广播、用户上线/下线通知等功能

 */

public class ChatServer {

    // 服务器监听端口

    private static final int PORT = 9876;

    // UDP套接字，用于接收和发送数据包

    private DatagramSocket socket;

    // 存储在线客户端信息的列表

    private List<ClientInfo> clients = new ArrayList<>();

    /**

     * 构造函数，初始化服务器

     */

    public ChatServer() {

        try {

            // 创建UDP套接字并绑定到指定端口

            socket = new DatagramSocket(PORT);

            System.out.println("服务器已启动，监听端口: " + PORT);

        } catch (SocketException e) {

            // 处理套接字创建失败的异常

            e.printStackTrace();

        }

    }

    /**

     * 启动服务器，开始接收和处理客户端消息

     */

    public void start() {

        // 创建接收数据的缓冲区

        byte[] buffer = new byte[1024];

        while (true) {

            try {

                // 创建接收数据包对象

                DatagramPacket receivePacket = new DatagramPacket(buffer, buffer.length);

                // 接收客户端发送的数据包（阻塞方法，直到收到数据）

                socket.receive(receivePacket);

                // 将接收到的字节数据转换为字符串，并去除首尾空格

                String message = new String(receivePacket.getData(), 0, receivePacket.getLength()).trim();

                // 获取发送方的IP地址

                String clientAddress = receivePacket.getAddress().getHostAddress();

                // 获取发送方的端口号

                int clientPort = receivePacket.getPort();

                // 处理客户端上线消息

                if (message.endsWith("上线了")) {

                    // 提取用户名（消息中"上线了"之前的部分）

                    String username = message.substring(0, message.indexOf("上线了")).trim();

                    // 创建客户端信息对象

                    ClientInfo client = new ClientInfo(username, receivePacket.getAddress(), clientPort);

                    // 将新客户端添加到在线列表

                    clients.add(client);

                    System.out.println(username + " 加入了聊天室");

                }

                // 处理客户端下线消息

                else if (message.endsWith("下线了")) {

                    // 遍历在线客户端列表

                    for (ClientInfo client : clients) {

                        // 找到发送下线消息的客户端

                        if (client.getAddress().equals(receivePacket.getAddress()) && client.getPort() == clientPort) {

                            // 从在线列表中移除该客户端

                            clients.remove(client);

                            System.out.println(client.getUsername() + " 离开了聊天室");

                            break;

                        }

                    }

                }

                // 广播消息给其他客户端（不包括发送者）

                for (ClientInfo client : clients) {

                    // 排除消息发送者

                    if (!(client.getAddress().equals(receivePacket.getAddress()) && client.getPort() == clientPort)) {

                        // 创建要发送的数据包（复用接收到的数据，直接转发）

                        DatagramPacket sendPacket = new DatagramPacket(

                                receivePacket.getData(),    // 数据内容

                                receivePacket.getLength(),  // 数据长度

                                client.getAddress(),        // 目标IP地址

                                client.getPort()            // 目标端口号

                        );

                        // 发送数据包

                        socket.send(sendPacket);

                    }

                }

            } catch (IOException e) {

                // 处理IO异常

                e.printStackTrace();

            }

        }

    }

    /**

     * 程序入口点

     */

    public static void main(String[] args) {

        // 创建服务器实例

        ChatServer server = new ChatServer();

        // 启动服务器

        server.start();

    }

    /**

     * 内部类：存储客户端信息

     */

    private static class ClientInfo {

        // 客户端用户名

        private String username;

        // 客户端IP地址

        private java.net.InetAddress address;

        // 客户端端口号

        private int port;

        /**

         * 构造函数，初始化客户端信息

         */

        public ClientInfo(String username, java.net.InetAddress address, int port) {

            this.username = username;

            this.address = address;

            this.port = port;

        }

        /**

         * 获取客户端用户名

         */

        public String getUsername() {

            return username;

        }

        /**

         * 获取客户端IP地址

         */

        public java.net.InetAddress getAddress() {

            return address;

        }

        /**

         * 获取客户端端口号

         */

        public int getPort() {

            // 获取端口

            return port;

        }

    }

}
